package com.tmc.service.intair;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.tmc.bean.common.CommonResult;
import com.tmc.bean.common.ContextInfo;
import com.tmc.bean.intair.EthFare;
import com.tmc.bean.intair.EthFlight;
import com.tmc.bean.intair.EthSegment;
import com.tmc.bean.intair.EthShoppingReq;
import com.tmc.bean.intair.EthShoppingResp;
import com.tmc.constant.CacheConstant;
import com.tmc.entity.baseinfo.Airline;
import com.tmc.entity.baseinfo.Airport;
import com.tmc.entity.intair.CommisionPolicy;
import com.tmc.entity.intair.PrivateFare;
import com.tmc.service.baseinfo.AirlineServiceImpl;
import com.tmc.service.baseinfo.AirportServiceImpl;
import com.tmc.service.cache.CacheServiceImpl;
import com.tmc.util.IntairUtil;
import com.tmc.util.ObjectUtil;
import com.tmc.vendor.intair.common.ServiceCenter;
import com.tmc.vendor.intair.common.VendorService;

@Service
public class EthShoppingServiceImpl {

	private static final int thread_size = 3;
	// private static final int timeout_seconds = 30;

	private static final String THREAD_PRIVATE_FARE = "THREAD_PRIVATE_FARE";
	private static final String THREAD_COMMISION_POLICY = "THREAD_COMMISION_POLICY";
	private static final String THREAD_SHOIPPING = "THREAD_SHOIPPING";

	private Log log = LogFactory.getLog(this.getClass());

	@Autowired
	private CommisionPolicyServiceImpl policyService;

	@Autowired
	private PrivateFareServiceImpl priFareService;

	@Autowired
	private AirportServiceImpl airportService;
	
	@Autowired
	private AirlineServiceImpl airlineService;
	
	@Autowired
	private CacheServiceImpl cache;

	public CommonResult search(final ContextInfo context, final String reqJSON, final String vendorCode) {
		String cacheKey = IntairUtil.getCacheKey(context, reqJSON);
		if (cache.get(cacheKey) != null) {
			return CommonResult.makeSuccess("成功", cache.get(cacheKey));
		}
		final EthShoppingReq req = JSON.parseObject(reqJSON, EthShoppingReq.class);
		CommonResult check = checkReq(req);
		if (!check.isSuccess()) {
			return check;
		}
		List<EthFare> fares = null;
		ExecutorService threadPool = Executors.newFixedThreadPool(thread_size);
		CompletionService<Entry<String, Object>> completion = new ExecutorCompletionService<Entry<String, Object>>(
				threadPool);
		// 调用shopping接口
		completion.submit(new Callable<Entry<String, Object>>() {
			@Override
			public Entry<String, Object> call() throws Exception {
				VendorService service = ServiceCenter.getService(vendorCode);
				EthShoppingResp resp = service.shopping(context, req, cache);
				return new AbstractMap.SimpleEntry<String, Object>(THREAD_SHOIPPING, resp);
			}
		});
		// 查询私有运价
		completion.submit(new Callable<Entry<String, Object>>() {
			@Override
			public Entry<String, Object> call() throws Exception {
				List<PrivateFare> privateFares = priFareService.findPolicys(context, req);
				return new AbstractMap.SimpleEntry<String, Object>(THREAD_PRIVATE_FARE, privateFares);
			}
		});
		// 查询返点政策
		completion.submit(new Callable<Entry<String, Object>>() {
			@Override
			public Entry<String, Object> call() throws Exception {
				List<CommisionPolicy> commisionPolicys = policyService.findPolicys(context, req);
				return new AbstractMap.SimpleEntry<String, Object>(THREAD_COMMISION_POLICY, commisionPolicys);
			}
		});
		// 获取结果
		Map<String, Object> map = null;
		try {
			map = this.getThreadPoolResult(completion);
		} catch (Exception e) {
			log.error("查询失败", e);
			return CommonResult.makeFail("查询失败！");
		}
		threadPool.shutdown();
		EthShoppingResp shoppingResp = (EthShoppingResp) map.get(THREAD_SHOIPPING);
		if (shoppingResp == null) {
			return CommonResult.makeFail("查询失败！");
		}
		fares = shoppingResp.getFares();
		Map<String, Map<String, EthFlight>> avMap = shoppingResp.getAvMap();
		// 填充基础信息， 机场对应城市code及名称
		log.error(new Date() + "----基础信息填充");
		this.fillExtInfo(fares, avMap);
		log.error(new Date() + "----匹配政策");
		// 匹配返点政策
		//fares = policyService.matchPolicy(fares, (List<CommisionPolicy>) map.get(THREAD_COMMISION_POLICY));
		// 匹配私有运价
		//fares = priFareService.matchPolicy(fares, avMap, (List<PrivateFare>) map.get(THREAD_PRIVATE_FARE));
		// TODO 过滤不合适中转
		// TODO 匹配相似航班
		// TODO 排序
		log.error(new Date() + "----运价排序");
		this.sortFares(fares);
		// 设置fareKey
		this.setFareKey(fares, reqJSON);
		//
		this.cacheFares(cacheKey, fares);
		return CommonResult.makeSuccess("成功", fares);
	}

	private void cacheFares(String cacheKey, List<EthFare> fares) {
		if (fares == null || fares.isEmpty()) {
			return;
		}
		cache.put(cacheKey, fares);
	}

	private void setFareKey(List<EthFare> fares, String reqJSON) {
		if (fares == null || fares.isEmpty()) {
			return;
		}
		Map<String, String> map = new HashMap<String, String>();
		for (EthFare fare : fares) {
			fare.setFareKey(UUID.randomUUID().toString().replaceAll("-", ""));
			map.put(fare.getFareKey(), reqJSON);
		}
		cache.put(CacheConstant.KEY_SHOPPING_FAREKEY, map);
	}

	public CommonResult getInBound(List<EthFare> fares, String fareKey) {
		if (fares == null || fares.isEmpty()) {
			return CommonResult.makeSuccess();
		}
		EthFare chooseFare = null;
		for (EthFare fare : fares) {
			if (fare.getFareKey().equals(fareKey)) {
				chooseFare = fare;
				break;
			}
		}
		if (chooseFare == null) {
			return CommonResult.makeFail("无此fareKey！");
		}
		String outboundFlightKey = this.getFlightKey(chooseFare.getFlights().get(0));
		List<EthFare> list = new ArrayList<EthFare>();
		for (EthFare fare : fares) {
			String flightKey = this.getFlightKey(fare.getFlights().get(0));
			if (flightKey.equals(outboundFlightKey)) {
				EthFare newFare = ObjectUtil.makeTargetBean(fare, EthFare.class);
				EthFlight flight = fare.getFlights().get(1);
				flight.setFlightIndex(2);
				newFare.setFlights(ObjectUtil.newList(flight));
				list.add(newFare);
			}
		}
		this.sortFares(list);
		return CommonResult.makeSuccess("成功", list);
	}

	public CommonResult getOutBound(List<EthFare> fares) {
		if (fares == null || fares.isEmpty()) {
			return CommonResult.makeSuccess();
		}
		Map<String, EthFare> map = new HashMap<String, EthFare>();
		for (EthFare fare : fares) {
			this.updateMap(map, fare);
		}
		List<EthFare> list = ObjectUtil.mapToList(map);
		this.sortFares(list);
		return CommonResult.makeSuccess("成功", list);
	}

	private void updateMap(Map<String, EthFare> map, EthFare fare) {
		EthFlight flight = fare.getFlights().get(0);
		flight.setFlightIndex(1);
		String flightKey = this.getFlightKey(flight);
		if (!map.containsKey(flightKey) || map.get(flightKey).getTotalAmount() > fare.getTotalAmount()) {
			// copy一个fare出来
			EthFare newFare = ObjectUtil.makeTargetBean(fare, EthFare.class);
			newFare.setFlights(ObjectUtil.newList(flight));
			map.put(flightKey, newFare);
		}
	}

	private String getFlightKey(EthFlight flight) {
		StringBuilder sb = new StringBuilder();
		for (EthSegment segment : flight.getSegments()) {
			sb.append(segment.getAirline()).append(segment.getFlightNo()).append("_");
		}
		return sb.toString();
	}

	private void fillExtInfo(List<EthFare> fares, Map<String, Map<String, EthFlight>> avMap) {
		Map<String, Airport> airportMap = airportService.findMapFromCache(null);
		Map<String, Airline> airlineMap = airlineService.findMapFromCache(null);
		if (fares != null && !fares.isEmpty()) {
			for (EthFare fare : fares) {
				for (EthFlight flight : fare.getFlights()) {
					this.fillExtInfo(airportMap, airlineMap, flight);
				}
			}
		}
		if (avMap != null && !avMap.isEmpty()) {
			for (String key : avMap.keySet()) {
				Map<String, EthFlight> map = avMap.get(key);
				for (String key1 : map.keySet()) {
					this.fillExtInfo(airportMap, airlineMap, map.get(key1));
				}
			}
		}
	}
	
	private String getEquipment(String equipment){
		if (ObjectUtil.noText(equipment)){
			return "";
		}
		if (equipment.startsWith("3")){
			return "空客A" + equipment;
		}
		if (equipment.startsWith("7")){
			return "波音" + equipment;
		}		
		return equipment;
	}

	private void fillExtInfo(Map<String, Airport> airportMap, Map<String, Airline> airlineMap, EthFlight flight) {
		for (EthSegment segment : flight.getSegments()) {
			Airport depart = airportMap.get(segment.getDeparture());
			Airport arrival = airportMap.get(segment.getArrival());
			Airline airline = airlineMap.get(segment.getAirline());
			if (depart != null){
				segment.setDepartureName(depart.getAirportName());
				segment.setDepartureCity(depart.getCityCode());
				segment.setDepartureCityName(depart.getCityName());
			}
			if (arrival != null){
				segment.setArrivalName(arrival.getAirportName());
				segment.setArrivalCity(arrival.getCityCode());
				segment.setArrivalCityName(arrival.getCityName());
			}
			if (airline != null){
				segment.setAirlineName(airline.getAirlineName());
			}
			segment.setEquipment(this.getEquipment(segment.getEquipment()));
		}
		EthSegment first = flight.getSegments().get(0);
		EthSegment last = flight.getSegments().get(flight.getSegments().size() - 1);
		if (flight.getSegments().size() > 1){
			flight.setTransfer(first.getArrival());
			flight.setTransferName(first.getArrivalName());
			flight.setTransferCity(first.getArrivalCity());
			flight.setTransferCityName(first.getArrivalCityName());
		}
		flight.setDeparture(first.getDeparture());
		flight.setArrival(last.getArrival());
		flight.setDepartureName(first.getDepartureName());
		flight.setArrivalName(last.getArrivalName());
		flight.setDepartureDate(first.getDepartureDate());
		flight.setArrivalDate(last.getArrivalDate());
		flight.setDepartureTime(first.getDepartureTime());
		flight.setArrivalTime(last.getArrivalTime());
		flight.setDepartureCity(first.getDepartureCity());
		flight.setArrivalCity(last.getArrivalCity());
		flight.setDepartureCityName(first.getDepartureCityName());
		flight.setArrivalCityName(last.getArrivalCityName());
		flight.setAirline(first.getAirline());
		flight.setAirlineName(first.getAirline().equals(last.getAirline()) ? first.getAirlineName() : first.getAirlineName() + "@" + last.getAirlineName());
		flight.setFlightNo(flight.getSegments().size() == 1 ? first.getAirline() + first.getFlightNo() : first.getAirline() + first.getFlightNo() + "@" + last.getAirline() + last.getFlightNo());
		flight.setTeminalDep(first.getTeminalDep());
		flight.setTeminalArr(last.getTeminalArr());
	}
	
	private void sortFares(List<EthFare> fares) {
		if (fares == null || fares.isEmpty()) {
			return;
		}
		Collections.sort(fares, new Comparator<EthFare>() {
			@Override
			public int compare(EthFare f1, EthFare f2) {
				if (f1.getTotalAmount() < f2.getTotalAmount()) {
					return -1;
				} else if (f1.getTotalAmount() > f2.getTotalAmount()) {
					return 1;
				}
				return 0;
			}
		});
	}

	private Map<String, Object> getThreadPoolResult(CompletionService<Entry<String, Object>> completion)
			throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();
		for (int i = 0; i < thread_size; i++) {
			Entry<String, Object> entry = completion.take().get();
			map.put(entry.getKey(), entry.getValue());
		}
		return map;
	}

	private CommonResult checkReq(EthShoppingReq req) {
		if (req == null || ObjectUtil.noText(req.getDeparture()) || ObjectUtil.noText(req.getArrival())) {
			return CommonResult.makeFail("出发到达地不能为空！");
		}
		if (ObjectUtil.noText(req.getDepartureDate())) {
			return CommonResult.makeFail("出发日期不能为空！");
		}
		if ("RT".equals(req.getFlightType()) && ObjectUtil.noText(req.getReturnDate())) {
			return CommonResult.makeFail("返程日期不能为空！");
		}
		return CommonResult.makeSuccess();
	}

}
